//
//  JMProgressCircleView.swift
//  RXSwift_Test
//
//  Created by JunMing on 2019/12/6.
//  Copyright © 2019 JMZhao. All rights reserved.
//

import UIKit

class JMProgressCircleView: UIView {

    // MARK: Properties
    private let circleView: JMCircleView = {
        let view = JMCircleView()
        view.lineWidth = 5
        view.circleColor = UIColor.colorFromHexString("#8B8989")
        view.startAngleRadians = -CGFloat.pi / 2
        view.endAngleRadians = view.startAngleRadians + 2 * .pi
        return view
    }()
    
    private var isAnimating = false
    var progressAnimationDuration: TimeInterval = 0.3
    var progress: CGFloat = 0 {
        didSet {
            if progress == 1 && isAnimating {
                if let currentAnimatedProgress = circleView.circleLayer.presentation()?.strokeEnd {
                    circleView.circleLayer.strokeEnd = currentAnimatedProgress
                    animateProgress(from: currentAnimatedProgress, to: progress)
                }
            }
            
            guard !isAnimating else { return }
            animateProgress(from: circleView.circleLayer.strokeEnd, to: progress)
        }
    }
    
    var lineWidth: CGFloat = 2 {
        didSet { circleView.lineWidth = lineWidth }
    }
    
    var circleColor: UIColor = UIColor.red {
        didSet { circleView.circleLayer.strokeColor = circleColor.cgColor }
    }
    
    // MARK: Initializers
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.isUserInteractionEnabled = false
        self.isHidden = true
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.isUserInteractionEnabled = false
        commonInit()
    }
    
    private func commonInit() {
        addSubview(circleView)
        animateProgress(from: 0, to: 0)
    }
    
    private func animateProgress(from startValue: CGFloat, to endValue: CGFloat) {
        isAnimating = true
        circleView.circleLayer.strokeEnd = endValue
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
        animation.fromValue = startValue
        animation.duration = progressAnimationDuration
        animation.delegate = self
        circleView.circleLayer.add(animation, forKey: "strokeEnd")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        circleView.frame = self.bounds
    }
}

extension JMProgressCircleView: CAAnimationDelegate {
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        isAnimating = !flag
        self.isHidden = true
    }
}

class JMCircleView: UIView {
    // MARK: Properties
    var startAngleRadians: CGFloat = -CGFloat.pi / 2
    var endAngleRadians: CGFloat = 3 * CGFloat.pi / 2
    var lineWidth: CGFloat = 1 {
        didSet {circleLayer.lineWidth = lineWidth}
    }
    var circleColor: UIColor = UIColor.red {
        didSet { circleLayer.strokeColor = circleColor.cgColor }
    }
    
    let circleLayer: CAShapeLayer = {
        let layer = CAShapeLayer()
        layer.fillColor = UIColor.clear.cgColor
        layer.lineCap = .round
        return layer
    }()
    
    // MARK: Initializers
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    
    private func commonInit() {
        backgroundColor = .clear
        circleLayer.strokeColor = circleColor.cgColor
        circleLayer.lineWidth = lineWidth
        layer.addSublayer(circleLayer)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        let radius = min(frame.width / 2, frame.height / 2) - lineWidth / 2
        let center = CGPoint(x: frame.width / 2, y: frame.height / 2)
        circleLayer.path = UIBezierPath(arcCenter: center,
                                        radius: radius,
                                        startAngle: startAngleRadians,
                                        endAngle: endAngleRadians,
                                        clockwise: true).cgPath
    }
    
    func startSpinning() {
        let animationKey = "rotation"
        layer.removeAnimation(forKey: animationKey)
        let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
        rotationAnimation.fromValue = 0.0
        rotationAnimation.toValue = CGFloat.pi * 2
        rotationAnimation.duration = 2
        rotationAnimation.repeatCount = .greatestFiniteMagnitude;
        layer.add(rotationAnimation, forKey: animationKey)
    }
}
